package com.klikmee.sms.core.base;

import java.text.MessageFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.log4j.Logger;
import org.springframework.core.task.TaskExecutor;

import com.klikmee.sms.core.base.communicator.Communicator;
import com.klikmee.sms.core.base.communicator.SendSmsIntercepter;
import com.klikmee.sms.core.base.dao.BulkMessageDAO;
import com.klikmee.sms.core.base.dao.IncomingMessageFacadeLocal;
import com.klikmee.sms.core.base.dao.OutgoingMessageFacadeLocal;
import com.klikmee.sms.core.base.dao.ServiceFacadeLocal;
import com.klikmee.sms.core.base.handlers.AbstractDeliveryHandler;
import com.klikmee.sms.core.base.postman.ServiceMessageDeliverer;
import com.klikmee.sms.core.base.util.Constants;
import com.klikmee.sms.core.base.util.States;
import com.klikmee.sms.core.model.BulkMessage;
import com.klikmee.sms.core.model.IncomingMessage;
import com.klikmee.sms.core.model.OutgoingMessage;
import com.klikmee.sms.core.model.PaymentInvoice;
import com.klikmee.sms.core.model.Provider;
import com.klikmee.sms.core.model.Service;
import com.klikmee.sms.core.model.ServiceChargingCategory;

public class Core {
	private Logger										logger									= Logger.getLogger(Core.class);
	private OutgoingMessageFacadeLocal					outgoingMessageDAO						= null;
	private IncomingMessageFacadeLocal					incomingMessageDAO						= null;
	private ServiceFacadeLocal							serviceDAO								= null;
	private BulkMessageDAO								bulkMessageDAO							= null;
	private TaskExecutor								taskExecutor							= null;
	// communicators
	private Communicator								mtsCommunicator							= null;
	private Communicator								telenorCommunicator						= null;
	private Communicator								vipCommunicator							= null;
	private MessageCreator								messageCreator							= null;
	private ServiceMessageDeliverer						messageDeliverer						= null;
	private List<Service>								servicesList							= null;
	private Hashtable<Integer, AbstractDeliveryHandler>	deliveryHandlerTable					= new Hashtable<Integer, AbstractDeliveryHandler>();
	private Service										freeOfChargeService						= null;
	private Service										badRequestService						= null;
	// misc
	private String										badSintaxMessageText					= null;
	private String										notEngoughCreditMessageText				= null;
	private String										serviceNotAvailableMessageText			= null;

	private Long										badRequestServiceId						= null;
	private Long										freeOfChargeServiceId					= null;

	// queues
	private BlockingQueue<IncomingMessage>				incomingMessageQueue					= new LinkedBlockingQueue<IncomingMessage>();
	private BlockingQueue<OutgoingMessage>				outgoingMessageQueue					= new LinkedBlockingQueue<OutgoingMessage>();
	private BlockingQueue<OutgoingMessage>				statusReportQueue						= new LinkedBlockingQueue<OutgoingMessage>();
	private BlockingQueue<BulkMessage>					bulkMessageQueue						= new LinkedBlockingQueue<BulkMessage>();

	// threads
	private Thread										incommingMessageQueueProcessingThread	= null;
	private Thread										outgoingMessageQueueProcessingThread	= null;
	private Thread										statusReportQueueProcessingThread		= null;
	private Thread										bulkMessageQueueProcessingThread		= null;

	/**
	 * Map of communicators configured for this instance of core context.
	 * Key is the name of the communicator identical to the value of {@link Provider#getName()} of the provider
	 * the communicator is implemented for. The value is and instance of communicator for that provider.
	 * Example:
	 * for MTS communicator value is MTS
	 * for VIP is VIP 
	 * and so on
	 * The names of each implemented communicator can be found in {@link Constants} class.
	 * 
	 */
	private Map<String, Communicator>					communicatorMap							= null;
	private boolean										stopQueueProcessing						= false;

	public Core() {
	}

	public void enqueueIncomingMessage(IncomingMessage incomingMessage) {
		try {
			incomingMessageQueue.put(incomingMessage);
		} catch (InterruptedException e) {
			logger.fatal("Interupted while waiting to enqueue incoming message. ", e);
		}
	}

	public void processIncomingMessageQueue() {

		try {

			IncomingMessage incomingMessage = incomingMessageQueue.take();
			this.onNewMessage(incomingMessage);

		} catch (InterruptedException e) {
			logger.fatal("Interupted while waiting to process incoming messages ", e);
		} catch (Exception e) {
			logger.fatal("Unexpected error while processing incoming queue ", e);
		}
	}

	public void enqueueOutgoingMessage(OutgoingMessage outgoingMessage) {
		try {
			outgoingMessageQueue.put(outgoingMessage);
		} catch (InterruptedException e) {
			logger.fatal("Interupted while waiting to enqueue outgoing message. ", e);
		}
	}

	public void processOutgoingMessageQueue() {

		try {

			OutgoingMessage outgoingMessage = outgoingMessageQueue.take();
			this.forwardMessageToCommunicator(outgoingMessage);

		} catch (InterruptedException e) {
			logger.fatal("Interupted while waiting to process outgoing messages ", e);
		} catch (Exception e) {
			logger.fatal("Unexpected error while processing outgoing queue ", e);
		}

	}

	public void enqueueBulkMessage(BulkMessage bulkMessage) {
		try {
			this.bulkMessageQueue.put(bulkMessage);
		} catch (InterruptedException e) {
			logger.fatal("Interupted while waiting to enqueue bulk message. ", e);
		}
	}

	public void processBulkMessageQueue() {

		try {

			BulkMessage bulkMessage = bulkMessageQueue.take();
			bulkMessage.setSendingTime(new Date());

			// dispatch bulk message to communicator
			Provider provider = bulkMessage.getProvider();

			if (provider.getName().equals(Constants.PROVIDER_MTS)) {
				mtsCommunicator.sendBulkMessage(bulkMessage);
			}

			else if (provider.getName().equals(Constants.PROVIDER_TELENOR)) {
				telenorCommunicator.sendBulkMessage(bulkMessage);
			}

			else if (provider.getName().equals(Constants.PROVIDER_VIP)) {
				vipCommunicator.sendBulkMessage(bulkMessage);
			}

		} catch (InterruptedException e) {
			logger.fatal("Interupted while waiting to process bulk messages ", e);
		} catch (Exception e) {
			logger.fatal("Unexpected error while processing bulk queue ", e);
		}
	}

	public void enqueueStatusReport(OutgoingMessage outgoingMessage) {
		try {
			this.statusReportQueue.put(outgoingMessage);
		} catch (InterruptedException e) {
			logger.fatal("Interupted while waiting to enqueue status message. ", e);
		}
	}

	public void processStatusReportQueue() {

		try {
			OutgoingMessage message = this.statusReportQueue.take();
			this.onDeliveryReceived(message);

		} catch (InterruptedException e) {
			logger.fatal("Interupted while waiting to process status report.", e);
		} catch (Exception e) {
			logger.fatal("Un exprected error while processing status report queue.", e);
		}
	}

	/**
	 * Forwards the outgoing message to appropriate communicator and modifies it
	 * accordingly.
	 * 
	 * @param outgoingMessage
	 *            a message to be sent
	 */
	public void forwardMessageToCommunicator(OutgoingMessage outgoingMessage) {

		// refresh outgoing msg from database
		// OutgoingMessage refreshed = this.outgoingMessageDAO.refresh(
		// outgoingMessage );
		OutgoingMessage refreshed = outgoingMessage;
		// if the message should be sent via MTS
		if (refreshed.getProvider().getName().equals(Constants.PROVIDER_MTS)) {

			// TODO: handle message sending exceptions from communicator
			mtsCommunicator.sendMessage(refreshed);

			logger.debug(String.format("outgoing message id = [%s] forwarded to MTS communicator", refreshed.getId()));
		}

		// if the message should be sent via Telenor
		else if (refreshed.getProvider().getName().equals(Constants.PROVIDER_TELENOR)) {
			telenorCommunicator.sendMessage(refreshed);
			logger.debug(String.format("outgoing message id = [%s] forwarded to Telenor communicator", refreshed.getId()));
		}

		// if the message should be sent via Vip
		// This part is not thread safe for answering on same incoming message.
		else if (refreshed.getProvider().getName().equals(Constants.PROVIDER_VIP)) {

			// add sequence number of reference id.
			// vip's reference id is mapped to
			// refreshed.ProvidersMesssageId
			String referenceID = refreshed.getProvidersMesssageId();

			Long sequenceNumber = this.outgoingMessageDAO.findNumberOfMessagesByProviderAndProvidersMessageId(refreshed.getProvider(), referenceID);
			String newReferenceId = generateVipBillingId(referenceID, sequenceNumber);

			refreshed.setProvidersMesssageId(newReferenceId);
			this.outgoingMessageDAO.edit(refreshed);

			vipCommunicator.sendMessage(refreshed);

			logger.debug(String.format("outgoing message id = [%s] forwarded to VIP communicator", refreshed.getId()));
		}
	}

	/**
	 * Sends the message via appropriate communicator. Communicator is resolved from {@link #communicatorMap}
	 * and each {@link SendSmsIntercepter} for that communicator is executed.
	 * Finaly message is sent by calling {@link Communicator#sendMessage(OutgoingMessage)} on the resolved communicator.
	 * @param outgoingMessage
	 */
	private void send(OutgoingMessage outgoingMessage){
		// resolve communicator used to send this message
		Communicator communicator = resolve(outgoingMessage);
		
		if(communicator == null){
			// throw exception if communicator could not be resolved
		}
		// execute intercepters assigned to this communicator, if any
		List<SendSmsIntercepter> smsIntercepters = communicator.getSendSmsIntercepters();
		
		for (SendSmsIntercepter intercepter : smsIntercepters) {
			intercepter.processMessage(outgoingMessage);
		}

		// forward message to communicator
		communicator.sendMessage(outgoingMessage);
		logger.info(MessageFormat.format("Message with id = [{0}] sent to {1} communicator", outgoingMessage.getId(), communicator));
	}
	
	/**
	 * Helper method for constructing vip billing Id for charged messages.
	 * 
	 * @param referenceId
	 * @param sequenceNumber
	 * @return referenceId appended by the sequenceId
	 */
	public String generateVipBillingId(String referenceId, Long sequenceNumber) {

		StringBuilder builder = new StringBuilder(referenceId);
		// check if billing id has already been set
		int indexOfMinus = referenceId.indexOf("-");
		if (indexOfMinus != -1) {
			// in this case remove number after - and set a new one
			builder.replace(indexOfMinus + 1, indexOfMinus + 2, sequenceNumber.toString());
		} else {
			// just append - [seq number]
			builder.append("-").append(sequenceNumber.toString());
		}

		return builder.toString();
	}

/**
     * callback from {@link #sendMessage(com.klikmee.sms.core.entities.OutgoingMessage)
     * @param outgoingMessage - should be same object as it was in method sendMessage
     * 
     */
	public void onMessageSent(OutgoingMessage outgoingMessage) {

		if (outgoingMessage == null) {
			logger.fatal("Could not process null core.OnMessageSent(), returning");
			return;
		}

		// set outgoing message state
		outgoingMessage.setState(States.OutgoingMessage.SENT);
		outgoingMessageDAO.edit(outgoingMessage);

		logger.debug(String.format("Message successfully sent id = [%s]", outgoingMessage.getId()));
	}

	/**
	 * Invoked by some of the communicators after successfully sending message.
	 * 
	 * @param bulkMessage
	 *            bulk message sent by communicator.
	 */

	public void onBulkMessageSent(BulkMessage bulkMessage) {
		// verify message
		if (bulkMessage == null) {
			return;
		}

		// just update state
		bulkMessage.setState(States.BulkMessage.SENT);

		bulkMessageDAO.edit(bulkMessage);

	}

	/**
	 * Callback from communicator when it receives new message. This method
	 * links the message to the service based on it's syntax. If massage has a
	 * wrong syntax it is linked to bad request service.
	 * 
	 * @param sms
	 * 
	 */
	public void onNewMessage(IncomingMessage newMessage) {

		// link the message to the service

		for (Service service : servicesList) {

			// check if new message's TO number is equal to service phone number
			if ((newMessage.getProvider().getName().equals(Constants.PROVIDER_MTS) && newMessage.getToNumber().equals(service.getMTSShortCode()))
					|| (newMessage.getProvider().getName().equals(Constants.PROVIDER_TELENOR) && newMessage.getToNumber().equals(service.getTelenorShorCode()))
					|| (newMessage.getProvider().getName().equals(Constants.PROVIDER_VIP) && newMessage.getToNumber().equals(service.getVIPShortCode()))) {
				// check if new message match service's syntax
				if (newMessage.getMessage().matches(service.getSintax())) {
					newMessage.setService(service);
					break;
				}
			}
		}

		// if messsage's syntax is not ok
		// set message's state to BAD SYNTAX (NOT REPLYED)
		// create outgoing message witch is charged as bad request service
		// set message's state to BAD SYNTAX (REPLYED)
		if (newMessage.getService() == null) {
			newMessage.setService(badRequestService);
			newMessage.setState(States.IncommingMessage.BAD_SYNTAX_NOTIFICATION_SENT);
			incomingMessageDAO.create(newMessage);

			ServiceChargingCategory serviceChargingCategory = getBadRequestService().getServiceChargingCategoryList().iterator().next();
			messageCreator.createAndEnqueueResponse(newMessage, serviceChargingCategory, badSintaxMessageText);
		}
		// if check messsage's syntax is ok
		// set message's state to SYNTAX CHECKED
		else {

			newMessage.setState(States.IncommingMessage.SYNTACTICALLY_OK);
			incomingMessageDAO.create(newMessage);

			// try to deliver message to service
			boolean messageDelivered = messageDeliverer.deliverMessage(newMessage);

			if (!messageDelivered) {
				// if message is not delivered to service, send info message to
				// user

				messageCreator.createAndEnqueueResponse(newMessage, this.getFreeOfChargeService().getServiceChargingCategoryList().iterator().next(), this.serviceNotAvailableMessageText);
				// and set im state
				newMessage.setState(States.IncommingMessage.SERVICE_NOT_AVAILABLE_NOTIFICATION_SENT);
				incomingMessageDAO.edit(newMessage);
			}

		}

	}

	/**
	 * Callback from communicator when new delivery is received. Step 1: link
	 * delivery report, represented by {@link OutgoingMessage Outgoing message}
	 * to send message, by examining provider field. If delivery could not be
	 * linked to sent message return and log this situation.
	 * 
	 * Step 2: if sent message does not have the payment invoice set it's status
	 * to delivered and return.
	 * 
	 * Step 3: Resolve payment invoice type
	 * 
	 * 
	 * @param deliveredMessage
	 */
	public void onDeliveryReceived(OutgoingMessage deliveredMessage) {

		// this the actual message to be found using data from parameter
		OutgoingMessage outgoingMessage = null;

		// use provider value to find outgoing message

		if (Constants.PROVIDER_MTS.equals(deliveredMessage.getProvider().getName())) {
			// in case of MTS correlator is OutgoingMessage Id itself
			// outgoingMessage =
			// outgoingMessageDAO.findByProvidersMessageIDAndProvider(
			// deliveredMessage.getProvidersMesssageId(), Constants.PROVIDER_MTS
			// );
			outgoingMessage = this.outgoingMessageDAO.find(deliveredMessage.getId());
		}
		// find vip's outgoing messages
		else if (Constants.PROVIDER_VIP.equals(deliveredMessage.getProvider().getName())) {

			// test if this is a bulk or charged message
			// charged messge will have providers msg id set
			if (deliveredMessage.getProvidersMesssageId() != null) {
				outgoingMessage = outgoingMessageDAO.findByProvidersMessageIDAndProvider(deliveredMessage.getProvidersMesssageId(), Constants.PROVIDER_VIP);
			}

			// bulk msg will have id set
			else if (deliveredMessage.getId() != null) {
				outgoingMessage = outgoingMessageDAO.findByMessageIDAndProvider(deliveredMessage.getId(), Constants.PROVIDER_VIP);
			}
		}

		// find telenor's outgoing messages
		else if (Constants.PROVIDER_TELENOR.equals(deliveredMessage.getProvider().getName())) {

			outgoingMessage = outgoingMessageDAO.findByMessageIDAndProvider(deliveredMessage.getId(), Constants.PROVIDER_TELENOR);
		}

		else if (Constants.PROVIDER_MTEL.equals(deliveredMessage.getProvider().getName())) {
			outgoingMessage = outgoingMessageDAO.findByProvidersMessageIDAndProvider(deliveredMessage.getProvidersMesssageId(), Constants.PROVIDER_MTEL);
		}

		// if outgoing message could not be found try with bulk message
		if (outgoingMessage == null) {
			// if no outgoing message could be found log it and return
			logger.fatal("Could not link delivery report to outgoing message id = " + deliveredMessage.getId());
			return;
		}

		// set status report
		outgoingMessage.setDeliveryStatus(deliveredMessage.getDeliveryStatus());

		// get payment invoice
		PaymentInvoice paymentInvoice = outgoingMessage.getPaymentInvoiceList().iterator().next();

		// get handler for this PI type
		AbstractDeliveryHandler deliveryHandler = deliveryHandlerTable.get(paymentInvoice.getType());
		// if handler is available, handle message
		if (deliveryHandler != null) {

			deliveryHandler.handle(outgoingMessage);

		} else {
			logger.fatal(String.format("Cound not resolve status report handler for outgoing message id = [%s]", outgoingMessage.getId()));
		}
	}

	/**
	 * Init method for initializing core resources
	 */
	public void init() {
		loadServicesDefinition();
		this.startQueueProcessingThreads();
		logger.info("Core initialized. ");
	}

	/**
	 * Starts threads for queue processing
	 */
	private void startQueueProcessingThreads() {
		// incoming message queue

		this.incommingMessageQueueProcessingThread = new Thread(new Runnable() {

			public void run() {
				while (!stopQueueProcessing) {
					Core.this.processIncomingMessageQueue();
				}

			}
		});

		this.incommingMessageQueueProcessingThread.start();
		logger.debug("Started processing incoming message queue...");

		// outgoing message queue
		this.outgoingMessageQueueProcessingThread = new Thread(new Runnable() {

			public void run() {
				while (!stopQueueProcessing) {
					Core.this.processOutgoingMessageQueue();
				}

			}
		});

		this.outgoingMessageQueueProcessingThread.start();
		logger.debug("Started processing outgoing message queue...");

		// status report queue
		this.statusReportQueueProcessingThread = new Thread(new Runnable() {

			public void run() {
				while (!stopQueueProcessing) {
					Core.this.processStatusReportQueue();
				}

			}
		});
		this.statusReportQueueProcessingThread.start();
		logger.info("Started processing status report queue...");
		// status report queue

		this.bulkMessageQueueProcessingThread = new Thread(new Runnable() {

			public void run() {
				while (!stopQueueProcessing) {
					Core.this.processBulkMessageQueue();
				}

			}
		});

		this.bulkMessageQueueProcessingThread.start();
		logger.debug("Started processing bulk message queue...");

	}

	/*
	 * utility method for loading service definitions from db. Loads all
	 * services plus bad request and free of charge service.
	 */
	public void loadServicesDefinition() {

		badRequestService = serviceDAO.find(this.badRequestServiceId);
		freeOfChargeService = serviceDAO.find(this.freeOfChargeServiceId);
		servicesList = serviceDAO.findAll();
		logger.info("Loaded " + servicesList.size() + " service definitions from database.");
	}

	public void destroy() {
		stopQueueProcessing = true;
		// interupt the threads
		this.incommingMessageQueueProcessingThread.interrupt();
		this.outgoingMessageQueueProcessingThread.interrupt();
		this.bulkMessageQueueProcessingThread.interrupt();
		this.statusReportQueueProcessingThread.interrupt();

		logger.info("Shuting down core completed.");
	}

	/**
	 * Resolves an instance of concrete communicator from {@link #communicatorMap} to be used to send
	 * outgoing message. Matching is done using {@link Provider#getName()}
	 * attached to the outgoing message
	 * 
	 * @param message
	 *            the actual message to be sent
	 * @return an instance of {@link Communicator} used to send the message, or null if no communicator could be resolved
	 */
	private Communicator resolve(OutgoingMessage message) {
		
		// get the name of provider associated with this message
		String providersName = message.getProvider().getName();
		
		// use this value to get instance of communicator from the map
		Communicator communicator = this.communicatorMap.get(providersName);
		
		return communicator;
	}

	public List<Service> getServicesList() {
		return servicesList;
	}

	public Service getFreeOfChargeService() {
		return freeOfChargeService;
	}

	public Service getBadRequestService() {
		return badRequestService;
	}

	public void setMtsCommunicator(Communicator mtsCommunicator) {
		this.mtsCommunicator = mtsCommunicator;
	}

	public void setTelenorCommunicator(Communicator telenorCommunicator) {
		this.telenorCommunicator = telenorCommunicator;
	}

	public void setVipCommunicator(Communicator vipCommunicator) {
		this.vipCommunicator = vipCommunicator;
	}

	public void setOutgoingMessageDAO(OutgoingMessageFacadeLocal outgoingMessageDAO) {
		this.outgoingMessageDAO = outgoingMessageDAO;
	}

	public String getNotEngoughCreditMessageText() {
		return notEngoughCreditMessageText;
	}

	public void setDeliveryHandlerTable(Hashtable<Integer, AbstractDeliveryHandler> deliveryHandlerTable) {
		this.deliveryHandlerTable = deliveryHandlerTable;
	}

	public Hashtable<Integer, AbstractDeliveryHandler> getDeliveryHandlerTable() {
		return deliveryHandlerTable;
	}

	public void setServiceDAO(ServiceFacadeLocal serviceDAO) {
		this.serviceDAO = serviceDAO;
	}

	public void setMessageCreator(MessageCreator billing) {
		this.messageCreator = billing;
	}

	public void setIncomintMessageDAO(IncomingMessageFacadeLocal incomintMessageDAO) {
		this.incomingMessageDAO = incomintMessageDAO;
	}

	public void setMessageDeliverer(ServiceMessageDeliverer messageDeliverer) {
		this.messageDeliverer = messageDeliverer;
	}

	public void setBadSintaxMessageText(String badSintaxMessageText) {
		this.badSintaxMessageText = badSintaxMessageText;
	}

	public void setServiceNotAvailableMessageText(String serviceNotAvailableMessageText) {
		this.serviceNotAvailableMessageText = serviceNotAvailableMessageText;
	}

	public void setBulkMessageDAO(BulkMessageDAO bulkMessageDAO) {
		this.bulkMessageDAO = bulkMessageDAO;
	}

	public void setNotEngoughCreditMessageText(String notEngoughCreditMessageText) {
		this.notEngoughCreditMessageText = notEngoughCreditMessageText;
	}

	public void setTaskExecutor(TaskExecutor taskExecutor) {
		this.taskExecutor = taskExecutor;
	}

	public String getBadSintaxMessageText() {
		return badSintaxMessageText;
	}

	public OutgoingMessageFacadeLocal getOutgoingMessageDAO() {
		return outgoingMessageDAO;
	}

	public IncomingMessageFacadeLocal getIncomingMessageDAO() {
		return incomingMessageDAO;
	}

	public ServiceFacadeLocal getServiceDAO() {
		return serviceDAO;
	}

	public BulkMessageDAO getBulkMessageDAO() {
		return bulkMessageDAO;
	}

	public TaskExecutor getTaskExecutor() {
		return taskExecutor;
	}

	public Communicator getMtsCommunicator() {
		return mtsCommunicator;
	}

	public Communicator getTelenorCommunicator() {
		return telenorCommunicator;
	}

	public Communicator getVipCommunicator() {
		return vipCommunicator;
	}

	public MessageCreator getMessageCreator() {
		return messageCreator;
	}

	public ServiceMessageDeliverer getMessageDeliverer() {
		return messageDeliverer;
	}

	public String getServiceNotAvailableMessageText() {
		return serviceNotAvailableMessageText;
	}

	public Logger getLogger() {
		return logger;
	}

	public BlockingQueue<IncomingMessage> getIncomingMessageQueue() {
		return incomingMessageQueue;
	}

	public BlockingQueue<OutgoingMessage> getOutgoingMessageQueue() {
		return outgoingMessageQueue;
	}

	public BlockingQueue<OutgoingMessage> getStatusReportQueue() {
		return statusReportQueue;
	}

	public BlockingQueue<BulkMessage> getBulkMessageQueue() {
		return bulkMessageQueue;
	}

	public Thread getIncommingMessageQueueProcessingThread() {
		return incommingMessageQueueProcessingThread;
	}

	public Thread getOutgoingMessageQueueProcessingThread() {
		return outgoingMessageQueueProcessingThread;
	}

	public Thread getStatusReportQueueProcessingThread() {
		return statusReportQueueProcessingThread;
	}

	public Thread getBulkMessageQueueProcessingThread() {
		return bulkMessageQueueProcessingThread;
	}

	public boolean isStopQueueProcessing() {
		return stopQueueProcessing;
	}

	public Long getBadRequestServiceId() {
		return badRequestServiceId;
	}

	public void setBadRequestServiceId(Long badRequestServiceId) {
		this.badRequestServiceId = badRequestServiceId;
	}

	public Long getFreeOfChargeServiceId() {
		return freeOfChargeServiceId;
	}

	public void setFreeOfChargeServiceId(Long freeOfChargeServiceId) {
		this.freeOfChargeServiceId = freeOfChargeServiceId;
	}

}
